import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
import fitz  # PyMuPDF
import os
from PIL import Image, ImageTk

class PDFViewer:
        

    def __init__(self, root):
        
        # 按下鼠标时
        def on_mouse_click(event):
            self.cut_x=event.x
            canvas_height = self.canvas.winfo_height()
            # 如果鼠标按钮被按下并且存在线条，则更新线条位置
            if self.canvas.itemcget(self.line_id, "fill")!= "":
                self.canvas.coords(self.line_id, event.x, 0, event.x, canvas_height)  # 更新线条坐标
            # 创建一条竖线，参数为起点和终点坐标
            else:
                self.line_id = self.canvas.create_line(event.x, 0, event.x, canvas_height, fill="red")

        # 窗口大小改变时
        def on_resize(event):
            self.show_page(self.current_page)
            canvas_height = self.canvas.winfo_height()
            if self.canvas.itemcget(self.line_id, "fill")!= "":
                self.canvas.coords(self.line_id, self.cut_x, 0, self.cut_x, canvas_height)  # 更新线条坐标
            elif self.cut_x > 0:
                self.line_id = self.canvas.create_line(self.cut_x, 0, self.cut_x, canvas_height, fill="red")

        self.root = root
        self.root.title("PDF分割")
        
        # 初始化变量
        self.file_path = None
        self.pdf_document = None
        self.current_page = 0 # 当前页码
        self.line_id = 0 # 分割线id
        self.cut_x = 0 # 分割线位置
        self.zoom = 1.0 # 缩放比例

        # 绑定窗口大小改变事件
        self.root.bind("<Configure>", on_resize)
        
        # 创建按钮框架
        self.button_frame = tk.Frame(root)
        self.button_frame.pack(side=tk.RIGHT, fill=tk.Y)

        # 创建画布
        self.canvas = tk.Canvas(root, bg='white')
        self.canvas.bind("<Button-1>", on_mouse_click)
        self.canvas.bind("<B1-Motion>", on_mouse_click)
        self.canvas.pack(fill=tk.BOTH, expand=True)
        
        # 创建按钮
        self.prev_button = tk.Button(self.button_frame, text='上一页', command=self.prev_page)
        self.prev_button.pack(side=tk.TOP,pady=10)
        
        self.next_button = tk.Button(self.button_frame, text='下一页', command=self.next_page)
        self.next_button.pack(side=tk.TOP,pady=5)
        
        self.rotation_button = tk.Button(self.button_frame, text='旋转', command=self.rotation_page)
        self.rotation_button.pack(side=tk.TOP,pady=5)

        self.page_label = tk.Label(self.button_frame, text='')
        self.page_label.pack(side=tk.TOP,pady=5)
        

        self.open_button = tk.Button(self.button_frame, text='打开PDF', command=self.open_pdf)
        self.open_button.pack(side=tk.BOTTOM,pady=10,padx=10)
        
        self.cut_button = tk.Button(self.button_frame, text='分割', command=self.cut_pdf)
        self.cut_button.pack(side=tk.BOTTOM,pady=5)

        self.del_button = tk.Button(self.button_frame, text='删除页', command=self.del_page)
        self.del_button.pack(side=tk.BOTTOM,pady=5)
        
        self.add_button = tk.Button(self.button_frame, text='添加页', command=self.add_page)
        self.add_button.pack(side=tk.BOTTOM,pady=5)
        
        self.save_button = tk.Button(self.button_frame, text='保存', command=self.save_pdf)
        self.save_button.pack(side=tk.BOTTOM,pady=5)
        
        self.image_button = tk.Button(self.button_frame, text='导出图片', command=self.save_image)
        self.image_button.pack(side=tk.BOTTOM,pady=5)

    # 分割页
    def cut_pdf(self):
        if self.pdf_document is None:
            messagebox.showinfo("Alert", "请先打开PDF！")
            return
        if self.line_id == 0:
            messagebox.showinfo("Alert", "请先划定分割线！")
            return
        x, y1, x, y2 = self.canvas.coords(self.line_id)
        page = self.pdf_document[self.current_page]

        zoom_factor = 4.0  # 从2.0提升到4.0（可配置）
        matrix = fitz.Matrix(zoom_factor, zoom_factor)
        pix_origin = page.get_pixmap(matrix=matrix, alpha=False)
        # pix_origin = page.get_pixmap(
        #     matrix=matrix,
        #     colorspace=fitz.csRGB,
        #     alpha=False,
        #     dpi=300  # 显式设置DPI
        # )
        pix_origin.set_origin(0, 0)

        # 计算分割位置
        cutx=int(x*zoom_factor/self.zoom)


        # 左侧图片
        pix_left=fitz.Pixmap(fitz.csRGB, (0,0,cutx, pix_origin.height),False)
        pix_left.set_origin(0, 0)
        pix_left.copy(pix_origin, (0, 0, cutx, pix_origin.height))
        # 右侧图片
        pix_right=fitz.Pixmap(fitz.csRGB, (0,0,pix_origin.width-cutx, pix_origin.height),False)
        pix_right.set_origin(0, 0)
        pix_origin.set_origin(-cutx, 0)
        pix_right.copy(pix_origin, (0, 0, pix_origin.width-cutx, pix_origin.height))
        
        # # # directory = os.path.dirname(self.file_path)
        # # # 保存为图片
        # # # pix_left.save(directory+'/left.png') #左侧图片路径
        # # # pix_right.save(directory+'/right.png') #右侧图片路径

        # 保存为PDF
        self.pdf_document.new_page(self.current_page+1, width=cutx, height=pix_origin.height)
        self.pdf_document.new_page(self.current_page+2, width=pix_origin.width-cutx, height=pix_origin.height)
        page_left = self.pdf_document[self.current_page+1]
        page_right = self.pdf_document[self.current_page+2]
        page_left.insert_image(fitz.Rect(0, 0, cutx, pix_origin.height), pixmap =pix_left)
        page_right.insert_image(fitz.Rect(0, 0, pix_origin.width-cutx, pix_origin.height), pixmap=pix_right)
        
        self.page_label.config(text = f"第{self.current_page+1}页 / 共{self.pdf_document.page_count}页")
        # self.pdf_document.save(directory+'/cut.pdf') #分割后的PDF路径
        # messagebox.showinfo("Alert", "分割完成。")

    # 添加页
    def add_page(self):
        if self.pdf_document is None:
            messagebox.showinfo("Alert", "请先打开PDF！")
            return
        # 打开文件选择对话框
        image_path = filedialog.askopenfilename(initialdir="/", title="选择图片文件", filetypes=(("图片文件", "*.jpg *.jpeg *.png *.gif *.bmp"), ("所有文件", "*.*")))
        if image_path:
            # 获取原pdf文件的宽度
            page = self.pdf_document[self.current_page]

            zoom_factor = 4.0  # 从2.0提升到4.0（可配置）
            matrix = fitz.Matrix(zoom_factor, zoom_factor)
            pix_origin = page.get_pixmap(matrix=matrix, alpha=False)
            # 新页面
            pix_new=fitz.Pixmap(image_path)
            #pix_new.set_origin(0, 0)
            #pix_new.copy(pix_origin, (0, 0, cutx, pix_origin.height))     
            # 在指定位置插入图片     
            self.pdf_document.new_page(self.current_page+1, width=pix_origin.width, height=pix_origin.height)
            new_page = self.pdf_document[self.current_page+1]
            new_page.insert_image(fitz.Rect(0, 0, pix_origin.width, pix_origin.height), pixmap =pix_new)
            # rect = fitz.Rect(0,0, width, height)
            # self.current_page.insert_image(rect, filename=image_path)
        else:
            messagebox.showinfo("Alert", "未选择图片文件！")
        

    # 删除页
    def del_page(self):
        if self.pdf_document is None:
            messagebox.showinfo("Alert", "请先打开PDF！")
            return
        if self.pdf_document.page_count==1:
            messagebox.showinfo("Alert", "只有一页不能删除！")
            return
        self.pdf_document.delete_page(self.current_page)
        if self.current_page>self.pdf_document.page_count-1:
            self.current_page=self.pdf_document.page_count-1
        self.show_page(self.current_page)

    # 打开pdf
    def open_pdf(self):
        self.file_path = filedialog.askopenfilename(filetypes=[("PDF Files", "*.pdf")])
        if self.file_path:
            self.pdf_document = fitz.open(self.file_path)
            self.current_page = 0
            self.show_page(self.current_page)

    # 保存pdf
    def save_pdf(self):
        if self.pdf_document is None:
            messagebox.showinfo("Alert", "请先打开PDF！")
            return
        file_path = filedialog.asksaveasfilename(filetypes=[("PDF Files", "*.pdf")])
        if file_path:
            self.pdf_document.save(file_path)
            messagebox.showinfo("Alert", "保存成功。")

    # 保存图片
    def save_image(self):
        if self.pdf_document is None:
            messagebox.showinfo("Alert", "请先打开PDF！")
            return
        dir_path = filedialog.askdirectory()

        # 获取文件名（包含扩展名）
        file_name_with_extension = os.path.basename(self.file_path)
        # 分割文件名和扩展名
        file_name, extension = os.path.splitext(file_name_with_extension)
        if dir_path:
            # 遍历每一页
            for i in range(self.pdf_document.page_count):
                page = self.pdf_document[i]
                # 每个尺寸的缩放系数为2，这将为我们生成分辨率提高四倍的图像。
                zoom_x = 2.0
                zoom_y = 2.0
                trans = fitz.Matrix(zoom_x, zoom_y)
                pix = page.get_pixmap(matrix=trans, alpha=False)
                pix.set_origin(0, 0)
                img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
                img.save(os.path.join(dir_path, f"{file_name}_{i+1}.png"))
            messagebox.showinfo("Alert", "导出完成。")

    # 显示页
    def show_page(self, page_number):
        if self.pdf_document is not None and 0 <= page_number < self.pdf_document.page_count:
            page = self.pdf_document[page_number]

            WIDTH = self.canvas.winfo_width()
            HEIGHT = self.canvas.winfo_height()
            x,y,width,height=page.rect  # 页面矩形
            if width / height < WIDTH / HEIGHT:
                # clip is narrower: zoom to window HEIGHT
                self.zoom = HEIGHT / height
            else:  # clip is broader: zoom to window WIDTH
                self.zoom = WIDTH / width
            mat = fitz.Matrix(self.zoom, self.zoom)
            pix = page.get_pixmap(matrix=mat)


            #pix = page.get_pixmap()
            img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
            img_tk = ImageTk.PhotoImage(img)
            
            self.canvas.delete("all")
            self.canvas.create_image(0, 0, anchor=tk.NW, image=img_tk)
            self.canvas.image = img_tk  # Keep a reference!

            self.page_label.config(text = f"第{self.current_page+1}页 / 共{self.pdf_document.page_count}页")

    # 上一页
    def prev_page(self):
        if self.pdf_document and self.current_page > 0:
            self.current_page -= 1
            self.show_page(self.current_page)
    
    # 下一页
    def next_page(self):
        if self.pdf_document and self.current_page < self.pdf_document.page_count - 1:
            self.current_page += 1
            self.show_page(self.current_page)
            
    # 旋转90度
    def rotation_page(self):
        if self.pdf_document:
            page = self.pdf_document[self.current_page]
            rotation=page.rotation+90
            if rotation>=360:
                rotation=rotation-360
            page.set_rotation(rotation)
            self.show_page(self.current_page)

if __name__ == "__main__":
    root = tk.Tk()
    viewer = PDFViewer(root)
    root.mainloop()